// ============ AI工具调度系统 - 内置工作区工具 ============

import type { ToolDefinition } from '../types';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { useWorkspaceStore } from '../../workspace';
import { addLocalHistorySnapshot } from '../../../assets/local-history';
import { useTimelineStore } from '../../timeline';
import { useAiTimelineStore } from '../../aiTimeline';

/**
 * 内置工作区内容搜索工具
 */
export const BUILTIN_WORKSPACE_SEARCH: ToolDefinition = {
  id: 'workspace.search',
  name: 'Workspace Content Search',
  description: 'Search code/content in the current workspace and return concise matches',
  parameters: {
    type: 'object',
    required: ['query'],
    properties: {
      query: { type: 'string' },
      directory: { type: 'string' }, // 可选，默认取 workspaceRoot
      include: { type: 'string' }, // 逗号分隔的包含模式
      exclude: { type: 'string' }, // 逗号分隔的排除模式
      regex: { type: 'boolean' },
      caseSensitive: { type: 'boolean' },
      wholeWord: { type: 'boolean' },
      maxResults: { type: 'integer', minimum: 1, maximum: 5000 },
      maxFileSize: { type: 'integer', minimum: 1 }
    }
  },
  metadata: {
    timeout: 30000,
    category: 'workspace',
    tags: ['search', 'workspace']
  },
  handler: async (params, context) => {
    const {
      query,
      directory,
      include,
      exclude,
      regex = false,
      caseSensitive = false,
      wholeWord = false,
      maxResults = 200,
      maxFileSize = 2 * 1024 * 1024,
    } = params || {};

    if (!query || typeof query !== 'string' || !query.trim()) {
      throw new Error('Parameter "query" is required');
    }

    const ws = useWorkspaceStore();
    const root = String(directory || ws.workspaceRoot || '');
    if (!root) {
      throw new Error('Workspace root is not set. Please open a workspace first.');
    }

    // 便于 LLM 展示的相对路径
    const toRelativePath = (absPath: string) => {
      const normAbs = (absPath || '').replace(/\\/g, '/');
      const normRoot = (root || '').replace(/\\/g, '/');
      if (normRoot && normAbs.toLowerCase().startsWith(normRoot.toLowerCase() + '/')) {
        return normAbs.slice(normRoot.length + 1);
      }
      return absPath;
    };

    // 启动后端流式搜索
    const searchId = await invoke<string>('start_content_search', {
      args: {
        directory: root,
        query: String(query),
        is_regex: !!regex,
        case_sensitive: !!caseSensitive,
        whole_word: !!wholeWord,
        include_pattern: include || undefined,
        exclude_pattern: exclude || undefined,
        max_results: maxResults,
        max_file_size: maxFileSize,
      }
    });

    // 聚合结果
    const fileMap = new Map<string, { path: string; relPath: string; name: string; matches: any[] }>();
    let total = 0;

    const addMatch = (m: any) => {
      const path = String(m.path || '');
      if (!fileMap.has(path)) {
        const name = path.split(/[\\\/]/).pop() || path;
        fileMap.set(path, { path, relPath: toRelativePath(path), name, matches: [] });
      }
      const file = fileMap.get(path)!;
      const sub = Array.isArray(m.submatches) && m.submatches[0] ? m.submatches[0] : null;
      const start = Number(sub?.start ?? 0);
      const end = Number(sub?.end ?? start);
      const lineText = String(m.line ?? '');
      const preview = {
        prefix: lineText.substring(0, start),
        hit: lineText.substring(start, end),
        suffix: lineText.substring(end),
      };
      const previewLines = Array.isArray(m.preview_lines) ? m.preview_lines : [];
      const isMultiline = (Number(m.end_line) && Number(m.start_line) && Number(m.end_line) > Number(m.start_line))
        || (typeof m.text === 'string' && m.text.includes('\n'))
        || (previewLines.length > 1);
      const extraPreview = isMultiline ? previewLines.slice(1, 3).join(' ⏎ ') : '';

      file.matches.push({
        line: Number(m.line_number) || 1,
        col: start + 1,
        snippet: `${preview.prefix}${preview.hit}${preview.suffix}${extraPreview ? ' ⏎ ' + extraPreview : ''}`.slice(0, 300),
        startLine: Number(m.start_line) || Number(m.line_number) || 1,
        startCol: start + 1,
        endLine: (() => {
          if (Number(m.end_line)) return Number(m.end_line);
          const text = String(m.text || '');
          const nl = (text.match(/\n/g) || []).length;
          return (Number(m.start_line) || Number(m.line_number) || 1) + nl;
        })(),
        endCol: (() => {
          if (Number(m.end_col)) return Number(m.end_col);
          const text = String(m.text || '');
          const nlParts = text.split('\n');
          if (nlParts.length > 1) {
            const last = nlParts[nlParts.length - 1] || '';
            return last.length + 1;
          }
          const end0 = Number(end);
          return (isFinite(end0) ? end0 : start) + 1;
        })(),
      });
      total += 1;
    };

    // 监听结果与完成事件
    let resolveDone: (() => void) | null = null;
    const donePromise = new Promise<void>((resolve) => {
      resolveDone = resolve;
    });

    const unlistenResults = await listen(`search:results:${searchId}`, (event: any) => {
      const matches = event?.payload;
      if (Array.isArray(matches)) {
        for (const m of matches) {
          if (total >= maxResults) break;
          addMatch(m);
        }
      }
    });

    const unlistenDone = await listen(`search:done:${searchId}`, (_event: any) => {
      resolveDone && resolveDone();
    });

    // 取消支持
    const abortHandler = async () => {
      try { await invoke('cancel_content_search', { args: { id: searchId } }); } catch {}
      resolveDone && resolveDone();
    };
    if (context?.signal) {
      if ((context.signal as any).aborted) {
        await abortHandler();
      } else {
        context.signal.addEventListener('abort', abortHandler, { once: true });
      }
    }

    // 等待完成
    await donePromise;

    // 清理监听
    try { unlistenResults(); } catch {}
    try { unlistenDone(); } catch {}

    // 整理输出（按文件路径排序，匹配按行列）
    const files = Array.from(fileMap.values())
      .map(f => ({
        ...f,
        matches: [...f.matches].sort((a, b) => (a.line === b.line ? a.col - b.col : a.line - b.line))
      }))
      .sort((a, b) => (a.path.replace(/\\/g, '/').toLowerCase().localeCompare(b.path.replace(/\\/g, '/').toLowerCase())));

    return {
      summary: { files: files.length, matches: total },
      results: files,
    };
  }
};

/**
 * 内置工作区文件编辑工具
 */
export const BUILTIN_WORKSPACE_APPLY_EDITS: ToolDefinition = {
  id: 'workspace.applyEdits',
  name: 'Workspace Apply Edits',
  description: 'Apply text edits to a specific file in the workspace with optional formatting',
  parameters: {
    type: 'object',
    properties: {
      path: { type: 'string' },
      edits: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            oldText: { type: 'string' },
            newText: { type: 'string' }
          },
          required: ['oldText', 'newText']
        }
      },
      // 兼容性：允许直接传 oldText/newText（自动包装成 edits 数组）
      oldText: { type: 'string' },
      newText: { type: 'string' },
      options: {
        type: 'object',
        properties: {
          preserveIndentation: { type: 'boolean' },
          normalizeWhitespace: { type: 'boolean' },
          partialMatch: { type: 'boolean' }
        }
      },
      // 兼容性：顶层选项（向后兼容）
      preserveIndentation: { type: 'boolean' },
      normalizeWhitespace: { type: 'boolean' },
      partialMatch: { type: 'boolean' },
      forceRefreshTimeline: { type: 'boolean' }
    },
    required: ['path']
  },
  metadata: {
    timeout: 30000,
    category: 'workspace',
    tags: ['edit', 'workspace']
  },
  handler: async (params, context) => {
    const {
      path,
      edits: editsInput,
      oldText,
      newText,
      options,
      forceRefreshTimeline = false
    } = params || {};

    if (!path || typeof path !== 'string') throw new Error('Parameter "path" is required');

    // 解析绝对路径（允许传相对路径），保持与工作区同样的分隔符风格，避免因不同分隔符导致本地历史 key 不一致
    const ws = useWorkspaceStore();
    const root = ws.workspaceRoot || '';
    const isAbsWin = /^[a-zA-Z]:[\\\\/]/.test(path) || path.startsWith('\\\\');
    const isAbsPosix = path.startsWith('/');

    const sep = (root && (root.includes('\\') || /^[a-zA-Z]:\\|^\\\\/.test(root))) ? '\\' : '/';

    let absPath = '';
    if (isAbsWin || isAbsPosix) {
      // 绝对路径：尽量转换为与工作区一致的分隔符风格（若有工作区根）
      absPath = root ? path.replace(/[\\/]/g, sep) : path;
    } else if (root) {
      const rel = path.replace(/[\\/]/g, sep);
      absPath = root.endsWith(sep) ? (root + rel) : (root + sep + rel);
    } else {
      absPath = path;
    }

    // 构建 edits 列表
    const edits: Array<{ oldText: string; newText: string }> = Array.isArray(editsInput) && editsInput.length
      ? editsInput
      : (typeof oldText === 'string' && typeof newText === 'string' ? [{ oldText, newText }] : []);

    if (!edits.length) throw new Error('No edits provided: either provide "edits" array, or "oldText" and "newText"');

    // 读取原始内容
    const original: string = await invoke('fs_read_text', { path: absPath });

    const opts = {
      preserveIndentation: (options && 'preserveIndentation' in options) ? !!options.preserveIndentation : (("preserveIndentation" in (params||{})) ? !!(params as any).preserveIndentation : true),
      normalizeWhitespace: (options && 'normalizeWhitespace' in options) ? !!options.normalizeWhitespace : (("normalizeWhitespace" in (params||{})) ? !!(params as any).normalizeWhitespace : true),
      partialMatch: (options && 'partialMatch' in options) ? !!options.partialMatch : (("partialMatch" in (params||{})) ? !!(params as any).partialMatch : true)
    };

    // 统计匹配位置（用于预览）
    const touchedLines = new Set<number>();
    const lineOffsets: number[] = [];
    {
      let acc = 0;
      const parts = original.split('\n');
      for (let i = 0; i < parts.length; i++) {
        lineOffsets.push(acc);
        acc += parts[i].length + 1; // +1 for "\n"
      }
    }

    function escapeRegExp(s: string) {
      return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    function countAndMark(content: string, search: string) {
      // 使用简单的全局查找统计并记录行号
      let count = 0;
      let idx = 0;
      while (true) {
        const found = content.indexOf(search, idx);
        if (found === -1) break;
        count++;
        idx = found + (search.length || 1);
        // 定位行号
        let line = 1;
        for (let i = 0; i < lineOffsets.length; i++) {
          const start = lineOffsets[i];
          const next = i + 1 < lineOffsets.length ? lineOffsets[i + 1] : Number.MAX_SAFE_INTEGER;
          if (found >= start && found < next) { line = i + 1; break; }
        }
        touchedLines.add(line);
      }
      return count;
    }

    // 先统计触达的行（基于原文）
    for (const e of edits) {
      if (!e.oldText) continue;
      countAndMark(original, e.oldText);
    }

    // 实际替换
    let newContent = original;
    let totalReplacements = 0;
    for (const e of edits) {
      const from = String(e.oldText ?? '');
      const to = String(e.newText ?? '');
      if (!from) continue;

      // 构造匹配模式
      const isWordy = /^\w+$/.test(from);
      const source = escapeRegExp(from);
      const pattern = new RegExp(
        opts.partialMatch ? source : (isWordy ? `\\b${source}\\b` : source),
        'g'
      );

      let replacementsForThisEdit = 0;
      newContent = newContent.replace(pattern, (match: string, offset: number, s: string) => {
        let replacement = to;
        if (opts.preserveIndentation && to.includes('\n')) {
          // 取当前匹配所在行的缩进
          const lineStart = s.lastIndexOf('\n', Math.max(0, offset - 1)) + 1;
          const lineSegment = s.slice(lineStart, offset);
          const lineIndent = (lineSegment.match(/^[\t ]*/) || [''])[0];
          const lines = to.split('\n');
          // 第一行保持原样，其余行补齐缩进
          replacement = lines
            .map((ln, idx) => (idx === 0 ? ln : lineIndent + ln))
            .join('\n');
        }
        replacementsForThisEdit++;
        return replacement;
      });
      totalReplacements += replacementsForThisEdit;
    }

    // 规范化空白（保持结构的轻量处理）
    if (opts.normalizeWhitespace) {
      // 统一行结尾为 \n
      newContent = newContent.replace(/\r\n?/g, '\n');
      // 去除行尾多余空格
      newContent = newContent.split('\n').map(l => l.replace(/[\t ]+$/g, '')).join('\n');
      // 保持文件末尾单个换行
      if (!newContent.endsWith('\n')) newContent += '\n';
    }

    const modified = newContent !== original;

    const beforeLines = original.split('\n');
    const afterLines = newContent.split('\n');
    const changeLines = Array.from(touchedLines).sort((a,b)=>a-b).slice(0, 20);
    const changes = changeLines.map(ln => ({
      line: ln,
      before: beforeLines[ln - 1] ?? '',
      after: afterLines[ln - 1] ?? ''
    }));

    if (!modified) {
      return {
        path: absPath,
        modified: false,
        replacements: 0,
        changes: []
      };
    }

    // 在写盘前保存"修改前"的本地历史快照
    try {
      await addLocalHistorySnapshot(absPath, original);
    } catch {}

    // 写回并记录时间线
    await invoke('fs_write_text', { path: absPath, content: newContent, createDirs: true });
    
    // 新增：记录 AI 专用时间线
    try {
      const ai = useAiTimelineStore();
      await ai.addEntry({
        kind: 'modify',
        path: absPath,
        tool: 'workspace.applyEdits',
        replacements: totalReplacements,
        changes,
        beforeContent: original,
        afterContent: newContent,
        fileSize: newContent.length
      });
    } catch {}

    // 若当前时间线正在展示该文件，或显式要求强刷，则立即强制刷新时间线
    try {
      const tl = useTimelineStore();
      const cur = tl.currentUri;
      const normalize = (s: string | undefined | null) => (s ? String(s).replace(/[\\\\/]/g, sep) : '');
      if (forceRefreshTimeline || (normalize(cur) && normalize(cur) === normalize(absPath))) {
        await tl.loadTimeline(absPath, true);
      }
    } catch {}

    return {
      path: absPath,
      modified: true,
      replacements: totalReplacements,
      changes
    };
  }
};